from dependencies.myRabbitmq.rabbitmqClient import RabbitClient
import pika


class AMQPUtil(RabbitClient):

    def __init__(self):
        super(AMQPUtil, self).__init__()

    def publish_message(self, routing_key, msg, exchange, delay=None, TTL=None):

        """
        发送消息到指定的交换器
        :param exchange: RabbitMQ交换器
        :param msg: 消息实体，是一个序列化的JSON字符串
        :return:
        """
        self.connect()
        if exchange != '':
            self.declare_exchange(exchange)

        if delay == 1:  # 支持延迟队列 ='RetryQueue'
            self.declare_delay_queue(routing_key, TTL=TTL)
        else:
            self.declare_queue(routing_key)

        self.declare_binding(routing_key, exchange)

        self.channel.basic_publish(exchange=exchange,
                                   routing_key=routing_key,
                                   body=msg,
                                   properties=pika.BasicProperties(
                                       delivery_mode=2,
                                       type=exchange
                                   ))
        print("message send out to {0}".format(exchange))
        self.close_connection()

    def start_consume(self, callback, queue):
        """
        启动消费者，开始消费RabbitMQ中的消息
        :return:
        """

        try:
            self.connect()
            self.channel.basic_qos(prefetch_count=1)
            # 消费消息
            self.channel.basic_consume(
                queue,  # 你要从那个队列里收消息
                callback,  # 如果收到消息，就调用callback函数来处理消息
                auto_ack=False,
            )
            self.channel.start_consuming()
        except KeyboardInterrupt:
            self.stop_consuming()

    def stop_consuming(self):
        self.channel.stop_consuming()
        self.close_connection()

    def message_handle_successfully(channel, method):
        """
        如果消息处理正常完成，必须调用此方法，
        否则RabbitMQ会认为消息处理不成功，重新将消息放回待执行队列中
        :param channel: 回调函数的channel参数
        :param method: 回调函数的method参数
        :return:
        """
        channel.basic_ack(delivery_tag=method.delivery_tag)

    def message_handle_failed(channel, method):
        """
        如果消息处理失败，应该调用此方法，会自动将消息放入异常队列
        :param channel: 回调函数的channel参数
        :param method: 回调函数的method参数
        :return:
        """
        channel.basic_reject(delivery_tag=method.delivery_tag, requeue=False)

    def declare_delay_queue(self, queue, DLX='RetryExchange', TTL=60000):
        """
        创建延迟队列
        :param TTL: ttl的单位是us，ttl=60000 表示 60s
        :param queue:
        :param DLX:死信转发的exchange
        :return:
        """
        arguments = {}
        if DLX:
            # 设置死信转发的exchange
            arguments['x-dead-letter-exchange'] = DLX
        if TTL:
            arguments['x-message-ttl'] = TTL
        print(arguments)
        self.channel.queue_declare(queue=queue,
                                   durable=True,
                                   arguments=arguments)

